Vue.js
ItIron2020
昨天我們了解到在vue中,父層如何利用props屬性傳遞資料給子層,藉此讓我們建立的組件能有預期的輸出結果。既然有上到下的資料傳遞,自然也會有下到上的溝通方式,這就是我們今天要談的emit客製化事件! 這兩天的內容稍微有些困難,時間許可的話我建議跟著範例玩幾次,實際操作後會去兩者如何溝通會更有概念! 我們馬上開始吧!
如果你有接觸過node.js,那我想你對於emit & on 的概念一定不陌生,在vue中也是基於完全一樣的概念來實現的。簡單的來說,emit可以讓你你建立一個全新事件,這個事件就像是我們常見的click、load、change等js事件;而on則是監聽到該事件時,你該做些什麼,我們先看一下簡單的概念範例。假設我今天想建立一個新事件叫做...delete-todo
子層(todo-list)
this.$emit('delete-todo') // 向上層傳第一個叫做delete-todo的事件
父層
<todo-list v-on:delete-todo="負責處理這事件的函數"></todo-list>
methods: {
負責處理這事件的函數() {
// 略
}
}
上方的範例可以讓你了解今天想達成的全貌,你可以發現這就像是一般的事件監聽處理,只是這個事件是來自子層的客製事件罷了! 沒有這麼複雜難懂,放心?
若你今天沒有要傳遞資料,只是單純的想通知父層現在有個客製化事件觸發了,記得去處理,那你可以採用剛剛示範的寫法。
this.$emit('delete-todo')
當然,很多時候我們會碰到要把子層的資料傳回父層的寫法,emit是可以接收第二個參數作為你想傳遞的資料,假設我今天想回傳title這個資料,寫法就會改為以下。
this.$emit('delete-todo', {
title: 'Some title'
})
真的相當簡單~沒騙你的!
我們接續昨天的範例,今天我們要讓那兩個按鈕生效! 讓刪除與完成代辦事項的功能可以順利執行。
這個問題問得很好,原因在於今天我們得到的資料是來自父層,不管是要刪除資料或是更新資料(那個todo)都只能在父層操作,子層並沒有辦法直接影響父層的資料。 實際上的資料流動會是這樣的概念
props傳遞資料
------------>
父層 子層
<------------
emit傳達客製事件
當我今天在子層點擊了刪除按鈕,觸發了我客製的事件delete-todo,父層監聽到delete-todo被觸發後,執行對應的處理函數,最終在父層刪除todos裡面的資料,而資料更新後會重新render,讓我們看到最後刪除的結果。
了解概念後我們馬上開始實作,首先請你在todo-list的組件中加入一個methods,我們就叫它deleteTodo吧!在這個函數裡面,我們要利用emit傳遞客製事件與資料給父層(給title讓父層知道要刪除哪一個) 同時利用v-on:click將它掛到垃圾桶的icon上面,表示點擊後要觸發這個事件。
Vue.component("todo-list", {
template: `
<div :class="[todo.isComplete? 'success':'error','todo-wrapper']">
<div class="todo-title">
{{todo.title}}
</div>
<div class="todo-icons">
<i class="fa fa-check" aria-hidden="true"></i>
<i class="fa fa-trash-alt" aria-hidden="true" @click="deleteTodo"></i> // 修改這裡
</div>
</div>
`,
props: {
todo: {
type: Object,
required: true
}
},
methods: { // 加入methods屬性
deleteTodo() {
this.$emit('delete-todo', {
title: this.todo.title
})
}
}
});
如果一開始的說明有看懂,剩下的部分你應該大概有想法了,首先我們要回到父層,在template中的子元件上監聽子層傳來的事件,並告訴它你這個事件我收到後,我打算用哪個函數來處理
<todo-list
v-for="todo in todos"
:key="todo.id"
:todo="todo"
@delete-todo="handleDeleteTodo">
</todo-list>
接著我們去下方methods的部分加入我們剛隨便寫的handleDeleteTodo函數,先用一個簡單的console確認我們是否真的收到來自子層的事件了。
export default {
data() {
return {
message: "Welcome to Vue!",
todos: todos
};
},
methods: {
handleDeleteTodo() {
console.log("get the event!");
}
}
};
此時你隨意點擊垃圾桶icon,你應該可以在console中看到我們設置的訊息
確認有收到事件後,我們就可以真正改寫父層的handle function了
請將handleDeleteTodo的內容改為以下,別忘了我們有從子層收到一包資料,它會是你handle function的第一個參數,看下方的範例應該很快就懂了
methods: {
handleDeleteTodo(payload) {
console.log(payload.title);
this.todos = this.todos.filter(item => item.title !== payload.title)
}
}
我特別將payload.title印出來,你可以發現那就是我們傳進去的參數
上方的範例當然也可以經由解構寫得更好看一點
methods: {
handleDeleteTodo({ title }) {
console.log(title);
this.todos = this.todos.filter(item => item.title !== title)
}
}
至此我們的刪除功能就可以正常運作了!! 透過以上的範例我想你們對於基本的事件傳遞也有了些許的認識,剩下的完成功能就交給你做囉:D 這裡有做完後的成品提供給你參考!
我們今天認識了如何用emit從子層傳遞資料給父層處理,這樣的溝通方式在小規模的專案中會相當的實用,不過之後專案規模大一點的時候,自然會有更適合的資料管理方式,這個我們就之後再提囉! 大家明天見!
此文章同步發布於個人部落格,有興趣的大大也可以來參觀一下:D